#pragma once

#include <iostream>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <string>
#include "err.hpp"
#include "log.hpp"

static const int defaultsock = -1;
static const int gbacklog = 32;
class Sock
{
public:
    Sock()
        : _sock(defaultsock)
    {
    }

    void SocKet()
    {
        int _sock = socket(AF_INET, SOCK_STREAM, 0);
        if(_sock == -1)
        {
            logMessage(Fatal, "socket error, code: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_ERR);
        }
    }
    void Bind(const uint16_t& port)
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));

        socklen_t len = sizeof(local);
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = INADDR_ANY;//任选一个服务器中的ip地址
        local.sin_port = htons(port);

        if(bind(_sock, (struct sockaddr*)&local, len) == -1)
        {
            logMessage(Fatal, "bind error, code: %d, errstring: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
    }

    void Listen()
    {
        if(listen(_sock, gbacklog) == -1)
        {
            logMessage(Fatal, "listen error, code: %d, errstring: %s", errno, strerror(errno));
            exit(LISTEN_ERR);
        }
    }

    int Accept(std::string* clientip, uint16_t* clientport)//输出型参数--客户端的ip和port
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int sock = accept(_sock, (struct sockaddr *)&peer, &len);
        if(sock== -1)
        {
            logMessage(Warning, "accept error, code: %d, errstring: %s", errno, strerror(errno));
        }
        else
        {
            *clientip = inet_ntoa(peer.sin_addr);//网络转本地字符串
            *clientport = ntohs(peer.sin_port);
        }
        return sock;//返回新得到的文件描述符
    }

    //客户端在连接的时候，需要知道对应服务器的ip和port，所以我们需要传入这两个参数
    int Connect(std::string& serverip, uint16_t& serverport)
    {
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        socklen_t len = sizeof(server);

        server.sin_addr.s_addr = inet_addr(serverip.c_str());//字符串转4字节，顺带转网络
        server.sin_port = htons(serverport);
        server.sin_family = AF_INET;

        return connect(_sock, (struct sockaddr*)&server, len);

    }

    int Fd()
    {
        return _sock;
    }

    ~Sock()
    {
        if(_sock != defaultsock)
        {
            close(_sock);
        }
    }

private:
    int _sock;
};